﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using HigLabo.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net;
using HigLabo.Net.Extensions;
using HigLabo.Core;

namespace HigLabo.Net.Facebook
{
    /// <summary>
    /// 
    /// </summary>
    public partial class FacebookClient : OAuth2Client
    {
        /// <summary>
        /// 
        /// </summary>
        public class RegexList
        {
            ///<summary>
            /// 
            ///</summary>
            public static readonly Regex OAuthToken = new Regex(@"code=([^&]*)");
        }
        public static readonly FacebookClientDefaultSettings Default = new FacebookClientDefaultSettings();

        public FacebookClient()
            : this("", "", "")
        {
        }
        public FacebookClient(String clientID, String clientSecret, String redirectUrl)
        {
            this.ClientID = clientID;
            this.ClientSecret = clientSecret;
            this.RedirectUrl = redirectUrl;
            this.AccessToken = new OAuth2AccessToken();
            this.AccessToken.SetProperty(Default.AccessToken);
        }

        public override string GetAuthorizeUrl(OAuth2ResponseType responseType)
        {
            return this.GetAuthorizeUrl(responseType, new List<String>());
        }
        public string GetAuthorizeUrl(OAuth2ResponseType responseType, List<String> scopes)
        {
            Func<String, String> f = HttpClient.UrlEncode;
            String baseUrl = String.Format("https://www.facebook.com/dialog/oauth?response_type={0}&client_id={1}&redirect_uri={2}"
                , responseType.ToStringFromEnum().ToLower(), f(this.ClientID), f(this.RedirectUrl));
            if (scopes.Count == 0)
            {
                return baseUrl;
            }
            else
            {
                StringBuilder sb = new StringBuilder(256);
                sb.Append(baseUrl);
                sb.Append("&scope=");
                for (int i = 0; i < scopes.Count; i++)
                {
                    sb.Append(f(scopes[i]));
                    if (i < scopes.Count - 1)
                    {
                        sb.Append(",");
                    }
                }
                return sb.ToString();
            }
        }
        protected override HttpRequestCommand CreateGetAccessTokenCommand(String code)
        {
            Func<String, String> f = UrlEncode;
            var url = String.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&redirect_uri={2}&code={3}"
                , f(this.ClientID), f(this.ClientSecret), f(this.RedirectUrl), f(code));
            var cm = new HttpRequestCommand(url);
            return cm;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        public HttpRequestCommand CreateCommand(HttpMethodName methodName, FacebookCommand command)
        {
            StringBuilder sb = new StringBuilder(256);
            String url = String.Format("https://graph.facebook.com/{0}?access_token={1}&limit={2}&fields=", command.GraphApiPath, this.AccessToken, command.Limit);

            if (command.Fields.Count > 0)
            {
                for (int i = 0; i < command.Fields.Count; i++)
                {
                    sb.Append(command.Fields[i].CreateQueryStringValue());
                    if (i < command.Fields.Count - 1)
                    {
                        sb.Append(",");
                    }
                }
            }
            url = url + HttpClient.UrlEncode(sb.ToString());
            if (command.HasData == true)
            {
                return this.CreateCommand(methodName, url, command.CreateDictionary());
            }
            else
            {
                return this.CreateCommand(methodName, url);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        public HttpRequestCommand CreateCommand(HttpMethodName methodName, String url)
        {
            return this.CreateCommand(methodName, url, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public HttpRequestCommand CreateCommand(HttpMethodName methodName, String url, Dictionary<String, String> data)
        {
            var cm = new HttpRequestCommand(url);
            cm.MethodName = methodName;
            if (data != null)
            {
                cm.SetBodyStream(new HttpBodyFormUrlEncodedData(Encoding.UTF8, data));
            }
            if (cm.MethodName != HttpMethodName.Get)
            {
                cm.IsSendBodyStream = true;
            }
            return cm;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<String> CreateJsonTextList(Dictionary<String, Object> data, String key)
        {
            if (data.ContainsKey(key) == false) { return new List<String>(); }
            var c = data[key] as JContainer;
            if (c == null) { return new List<string>(); }
            return CreateJsonTextList(c);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key1"></param>
        /// <param name="key2"></param>
        /// <returns></returns>
        public static List<String> CreateJsonTextList(Dictionary<String, Object> data, String key1, String key2)
        {
            if (data.ContainsKey(key1) == false) { return new List<String>(); }
            var d = JsonConvert.DeserializeObject<Dictionary<String, Object>>(data[key1].ToString());
            return CreateJsonTextList(d, key2);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        /// <returns></returns>
        public static List<String> CreateJsonTextList(JContainer container)
        {
            List<String> l = new List<string>();

            foreach (Object o in container)
            {
                l.Add(o.ToString());
            }
            return l;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<String> CreateTextList(Dictionary<String, Object> data, String key)
        {
            if (data.ContainsKey(key) == false) { return new List<String>(); }
            var c = data[key] as JContainer;
            if (c == null) { return new List<string>(); }
            return CreateTextList(c);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        /// <returns></returns>
        public static List<String> CreateTextList(JContainer container)
        {
            List<String> l = new List<string>();
            JValue v = null;

            foreach (Object o in container)
            {
                v = o as JValue;
                if (v != null && v.Type == JTokenType.String)
                {
                    l.Add(v.Value.ToString());
                }
                else
                {
                    l.Add(o.ToString());
                }
            }
            return l;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<String> CreateTagJsonTextList(Dictionary<String, Object> data, String key)
        {
            List<String> l = new List<string>();
            var dd = JsonConvert.DeserializeObject<Dictionary<String, Object>>(data.ToString(key));
            foreach (var tag in dd.Keys)
            {
                if (dd[tag] == null) { continue; }
                foreach (var s in FacebookClient.CreateJsonTextList(dd, tag))
                {
                    l.Add(s);
                }
            }
            return l;
        }
        private void GetBodyText(FacebookCommand command, Action<String> callback)
        {
            this.GetBodyText(HttpMethodName.Get, command, callback);
        }
        private void GetBodyText(HttpMethodName methodName, FacebookCommand command, Action<String> callback)
        {
            var cm = this.CreateCommand(methodName, command);
            this.GetBodyText(cm, callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetUser(Action<User> callback)
        {
            this.GetUser("me", callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetUser(String id, Action<User> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new User(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetUser(GetObjectCommand command, Action<User> callback)
        {
            this.GetBodyText(command, text => callback(new User(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetPage(String id, Action<Page> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new Page(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetPage(GetObjectCommand command, Action<Page> callback)
        {
            this.GetBodyText(command, text => callback(new Page(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetHome(Action<PostData> callback)
        {
            this.GetHome("me", callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetHome(String id, Action<PostData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Home), text => callback(new PostData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetHome(GetObjectCommand command, Action<PostData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Home), text => callback(new PostData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetFeed(Action<PostData> callback)
        {
            this.GetFeed("me", callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetFeed(String id, Action<PostData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Feed), text => callback(new PostData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetFeed(GetObjectCommand command, Action<PostData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Feed), text => callback(new PostData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetStatuses(Action<PostData> callback)
        {
            this.GetStatuses("me", callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetStatuses(String id, Action<PostData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Statuses), text => callback(new PostData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetStatuses(GetObjectCommand command, Action<PostData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Statuses), text => callback(new PostData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetPostData(PostData data, PagingMode mode, Action<PostData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetPostData(cm, callback);
        }
        private void GetPostData(HttpRequestCommand command, Action<PostData> callback)
        {
            this.GetBodyText(command, text => callback(new PostData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetLikes(String id, Action<LikeData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Likes), text => callback(new LikeData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetLikes(GetObjectCommand command, Action<LikeData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Likes), text => callback(new LikeData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetLikes(LikeData data, PagingMode mode, Action<LikeData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetLikes(cm, callback);
        }
        private void GetLikes(HttpRequestCommand command, Action<LikeData> callback)
        {
            this.GetBodyText(command, text => callback(new LikeData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetComment(String id, Action<Comment> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new Comment(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetComment(GetObjectCommand command, Action<Comment> callback)
        {
            this.GetBodyText(command, text => callback(new Comment(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetComments(String id, Action<CommentData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Comments), text => callback(new CommentData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetComments(GetObjectCommand command, Action<CommentData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Comments), text => callback(new CommentData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetComments(CommentData data, PagingMode mode, Action<CommentData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetComments(cm, callback);
        }
        private void GetComments(HttpRequestCommand command, Action<CommentData> callback)
        {
            this.GetBodyText(command, text => callback(new CommentData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetAlbum(String id, Action<Album> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new Album(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetAlbums(String id, Action<AlbumData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Albums), text => callback(new AlbumData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetAlbums(GetObjectCommand command, Action<AlbumData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Albums), text => callback(new AlbumData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetAlbums(AlbumData data, PagingMode mode, Action<AlbumData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetAlbums(cm, callback);
        }
        private void GetAlbums(HttpRequestCommand command, Action<AlbumData> callback)
        {
            this.GetBodyText(command, text => callback(new AlbumData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetBook(String id, Action<Book> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new Book(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetBook(GetObjectCommand command, Action<Book> callback)
        {
            this.GetBodyText(command, text => callback(new Book(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetBooks(String id, Action<BookData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Books), text => callback(new BookData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetBooks(GetObjectCommand command, Action<BookData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Books), text => callback(new BookData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetBooks(BookData data, PagingMode mode, Action<BookData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetBodyText(cm, text => callback(new BookData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetMovie(String id, Action<Movie> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new Movie(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetMovies(String id, Action<MovieData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Movies), text => callback(new MovieData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetMovies(GetObjectCommand command, Action<MovieData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Movies), text => callback(new MovieData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetMovies(MovieData data, PagingMode mode, Action<MovieData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetMovies(cm, callback);
        }
        private void GetMovies(HttpRequestCommand command, Action<MovieData> callback)
        {
            this.GetBodyText(command, text => callback(new MovieData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetMusic(String id, Action<Music> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new Music(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetMusicList(String id, Action<MusicData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Music), text => callback(new MusicData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetMusicList(GetObjectCommand command, Action<MusicData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Music), text => callback(new MusicData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetMusicList(MusicData data, PagingMode mode, Action<MusicData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetMusicList(cm, callback);
        }
        private void GetMusicList(HttpRequestCommand command, Action<MusicData> callback)
        {
            this.GetBodyText(command, text => callback(new MusicData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetTelevision(String id, Action<Television> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new Television(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetTelevisions(String id, Action<TelevisionData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Television), text => callback(new TelevisionData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetTelevisions(GetObjectCommand command, Action<TelevisionData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Television), text => callback(new TelevisionData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetTelevisions(TelevisionData data, PagingMode mode, Action<TelevisionData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetTelevisions(cm, callback);
        }
        private void GetTelevisions(HttpRequestCommand command, Action<TelevisionData> callback)
        {
            this.GetBodyText(command, text => callback(new TelevisionData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetFriend(String id, Action<User> callback)
        {
            this.GetBodyText(new GetObjectCommand(id), text => callback(new User(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetFriends(Action<FriendData> callback)
        {
            this.GetFriends("me", callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void GetFriends(String id, Action<FriendData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(id, FacebookConnetionType.Friends), text => callback(new FriendData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void GetFriends(GetObjectCommand command, Action<FriendData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand(command, FacebookConnetionType.Friends), text => callback(new FriendData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetFriends(FriendData data, PagingMode mode, Action<FriendData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetFriends(cm, callback);
        }
        private void GetFriends(HttpRequestCommand command, Action<FriendData> callback)
        {
            this.GetBodyText(command, text => callback(new FriendData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetNotifications(Action<NotificationData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand("me", FacebookConnetionType.Notifications), text => callback(new NotificationData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetNotifications(NotificationData data, PagingMode mode, Action<NotificationData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetNotifications(cm, callback);
        }
        private void GetNotifications(HttpRequestCommand command, Action<NotificationData> callback)
        {
            this.GetBodyText(command, text => callback(new NotificationData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetInbox(Action<InboxData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand("me", FacebookConnetionType.Inbox), text => callback(new InboxData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetInbox(InboxData data, PagingMode mode, Action<InboxData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetInbox(cm, callback);
        }
        private void GetInbox(HttpRequestCommand command, Action<InboxData> callback)
        {
            this.GetBodyText(command, text => callback(new InboxData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void GetOutbox(Action<OutboxData> callback)
        {
            this.GetBodyText(new GetObjectConnectionCommand("me", FacebookConnetionType.Outbox), text => callback(new OutboxData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <param name="callback"></param>
        public void GetOutbox(OutboxData data, PagingMode mode, Action<OutboxData> callback)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            this.GetOutbox(cm, callback);
        }
        private void GetOutbox(HttpRequestCommand command, Action<OutboxData> callback)
        {
            this.GetBodyText(command, text => callback(new OutboxData(text)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void Like(String id, Action<Boolean> callback)
        {
            var command = new FacebookCommand(id + "/likes");
            this.GetBodyText(HttpMethodName.Post, command, text => callback(String.Equals(text, "true", StringComparison.OrdinalIgnoreCase)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void UnLike(String id, Action<Boolean> callback)
        {
            var command = new FacebookCommand(id + "/likes");
            this.GetBodyText(HttpMethodName.Delete, command, text => callback(String.Equals(text, "true", StringComparison.OrdinalIgnoreCase)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void AddComment(AddCommentCommand command, Action<String> callback)
        {
            this.GetBodyText(HttpMethodName.Post, command, text =>
            {
                var d = JsonConvert.DeserializeObject<Dictionary<String, Object>>(text);
                var id = d.ToString("id");
                callback(id);
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        public void AddStatus(AddStatusCommand command, Action<String> callback)
        {
            this.GetBodyText(HttpMethodName.Post, command, text =>
            {
                var d = JsonConvert.DeserializeObject<Dictionary<String, Object>>(text);
                var id = d.ToString("id");
                callback(id);
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="callback"></param>
        public void DeleteObject(String id, Action<Boolean> callback)
        {
            var cm = new FacebookCommand(id);
            this.GetBodyText(HttpMethodName.Delete, cm, text => callback(String.Equals(text, "true", StringComparison.OrdinalIgnoreCase)));
        }
        private void DeleteObject(FacebookCommand command, Action<Boolean> callback)
        {
            this.GetBodyText(HttpMethodName.Delete, command, text => callback(String.Equals(text, "true", StringComparison.OrdinalIgnoreCase)));
        }
    }
}
